
package cz.muni.fi.pa165.carpark.servicies;

import cz.muni.fi.pa165.carpark.TO.BusinessTripTO;
import cz.muni.fi.pa165.carpark.TO.EmployeeTO;
import cz.muni.fi.pa165.carpark.TO.VehicleTO;
import cz.muni.fi.pa165.carpark.VehicleStatus;
import cz.muni.fi.pa165.carpark.dao.BusinessTripDAO;
import cz.muni.fi.pa165.carpark.dao.VehicleDAO;
import cz.muni.fi.pa165.carpark.entities.BusinessTrip;
import cz.muni.fi.pa165.carpark.entities.Employee;
import cz.muni.fi.pa165.carpark.entities.Vehicle;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.convert.ConversionService;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 *
 * @author xmarton1
 */
@Service
public class BusinessTripServiceImpl implements BusinessTripService{
    
    @Autowired
    private BusinessTripDAO businessTripDAO;
    
    @Autowired
    private VehicleDAO vehicleDAO;
    
    @Autowired
    @Qualifier("TOconverter")
    private ConversionService convertor;

    @PreAuthorize("hasRole('employee_manager') or hasRole('superadmin')")
    @Override
    @Transactional
    public void create(BusinessTripTO businessTrip) {
        if(businessTrip==null || businessTrip.getVehicle()==null)
            throw new DataIntegrityViolationException("Trip or vehicle is null");
        BusinessTrip bt = convertor.convert(businessTrip, BusinessTrip.class);
        // change Vehicle status to USED
        Vehicle tripVehicle = bt.getVehicle();
        tripVehicle.setStatus(VehicleStatus.USED);
        vehicleDAO.update(tripVehicle);
        //
        businessTripDAO.create(bt);
        businessTrip.setId(bt.getId());
    }

    @PreAuthorize("hasRole('employee_manager') or hasRole('superadmin')")
    @Override
    @Transactional
    public BusinessTripTO retrieve(Long id) {
        BusinessTrip bt =  businessTripDAO.read(id);
        BusinessTripTO btto = convertor.convert(bt, BusinessTripTO.class);
        return btto;
    }

    @PreAuthorize("hasRole('employee_manager') or hasRole('superadmin')")
    @Override
    @Transactional
    public void update(BusinessTripTO businessTrip) {
        BusinessTrip bt = convertor.convert(businessTrip, BusinessTrip.class);
        businessTripDAO.update(bt);
    }

    @PreAuthorize("hasRole('employee_manager') or hasRole('superadmin')")
    @Override
    @Transactional
    public void delete(BusinessTripTO businessTrip) {
        BusinessTrip bt = convertor.convert(businessTrip, BusinessTrip.class);
        //
        Vehicle vehicle = bt.getVehicle();
        if(vehicle.getStatus()== VehicleStatus.USED && bt.getNumberOfDrivenKms() == 0){
            vehicle.setStatus(VehicleStatus.AVAILABLE);
            vehicleDAO.update(vehicle);
        }
        //
        businessTripDAO.delete(bt);
    }
    
    @PreAuthorize("hasRole('employee_manager') or hasRole('superadmin')")
    @Override
    @Transactional
    public void cancelAbsolvedTrip(BusinessTripTO businessTrip,int drivenKilometers){
        businessTrip.setNumberOfDrivenKms(drivenKilometers);
        BusinessTrip bt = convertor.convert(businessTrip, BusinessTrip.class);
        businessTripDAO.update(bt);
        // get Vehicle
        Vehicle vehicle = bt.getVehicle();
        int kms = vehicle.getNumberOfKms() + drivenKilometers;
        vehicle.setNumberOfKms(kms);
        vehicle.setStatus(VehicleStatus.AVAILABLE);
        vehicleDAO.update(vehicle);
    }

    @PreAuthorize("hasRole('employee_manager') or hasRole('superadmin')")
    @Override
    @Transactional
    public List<BusinessTripTO> retriveEmployeeBusinessTrips(EmployeeTO employee) {
        Employee emp = convertor.convert(employee, Employee.class);
        List<BusinessTrip> bts = businessTripDAO.getEmployeeBusinessTrips(emp);
        List<BusinessTripTO> bttos = new LinkedList<BusinessTripTO>();
        for(BusinessTrip bt : bts)
        {
            bttos.add(convertor.convert(bt, BusinessTripTO.class));
        }
        return bttos;
    }

    @PreAuthorize("hasRole('employee_manager') or hasRole('superadmin') or hasRole('vehicle_manager')")
    @Override
    @Transactional
    public List<BusinessTripTO> retrieveVehiclesBusinessTrips(VehicleTO vehicle) {
        Vehicle veh = convertor.convert(vehicle, Vehicle.class);
        List<BusinessTrip> bts = businessTripDAO.getVehiclesBusinessTrips(veh);
        List<BusinessTripTO> bttos = new LinkedList<BusinessTripTO>();
        for(BusinessTrip bt : bts)
        {
            bttos.add(convertor.convert(bt, BusinessTripTO.class));
        }
        return bttos;
    }

    @PreAuthorize("hasRole('employee_manager') or hasRole('superadmin')")
    @Override
    @Transactional
    public List<BusinessTripTO> retrieveAll() {
        List<BusinessTrip> bts = businessTripDAO.findAll();
        List<BusinessTripTO> bttos = new LinkedList<BusinessTripTO>();
        for(BusinessTrip bt : bts)
        {
            bttos.add(convertor.convert(bt, BusinessTripTO.class));
        }
        return bttos;
    }

    public void setBusinessTripDAO(BusinessTripDAO businessTripDAO) {
        this.businessTripDAO = businessTripDAO;
    }

    public void setConvertor(ConversionService convertor) {
        this.convertor = convertor;
    }
    
    @PreAuthorize("hasRole('employee_manager') or hasRole('superadmin')")
    @Override
    public List<BusinessTripTO> retrieveByDates(List<BusinessTripTO> trips,Date beginDate,Date endDate){
        List<BusinessTripTO> reslutList = new ArrayList<BusinessTripTO>();
        
        for(BusinessTripTO trip : trips){
            if(trip.getDateOfTrip().after(beginDate) && trip.getDateOfTrip().before(endDate)
               || trip.getDateOfTrip().equals(beginDate) || trip.getDateOfTrip().equals(endDate)){
                reslutList.add(trip);
            }
        }
        return reslutList;
    }
    
    

}
